﻿#region Copyright (c) 2000-2011 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2011 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2010 Developer Express Inc.

namespace DevExpress.OAuth {
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Diagnostics;
    using System.Net;
    using System.IO;
#if TEST
    using DevExpress.OAuth.Provider;
#endif

    public class ConsumerBase : IConsumer {
        Uri _callbackUri;
        /// <summary>
        /// Specifies the callback URI to be used when making a request. OAuth: oauth_callback
        /// </summary>
        public Uri CallbackUri {
            get {
                return _callbackUri;
            }
            set {
                _callbackUri = value;
            }
        }

        string _consumerKey;
        /// <summary>
        /// Specifies the consumer key to be used when making a request. OAuth: oauth_consumer_key
        /// </summary>
        public string ConsumerKey {
            get {
                return _consumerKey;
            }
            set {
                _consumerKey = value;
            }
        }

        string _consumerSecret;
        /// <summary>
        /// Specifies the consumer secret to be used when making a request. OAuth: oauth_consumer_secret
        /// </summary>
        public string ConsumerSecret {
            get {
                return _consumerSecret;
            }
            set {
                _consumerSecret = value;
            }
        }
    }

    public class Consumer : ConsumerBase {
        public static HttpWebRequest GetRequest(Uri requestUri, string httpMethod, CookieContainer cookies) {
            if (requestUri == null) {
                throw new ArgumentNullException("requestUri");
            }
            if (httpMethod == null || httpMethod.Length == 0) {
                throw new ArgumentNullException("httpMethod");
            }
            if (!requestUri.IsAbsoluteUri) {
                throw new InvalidOperationException("Request URI be absolute.");
            }
            HttpWebRequest httpRequest
                = (HttpWebRequest)HttpWebRequest.Create(requestUri);
            httpRequest.Method = httpMethod;
            if (String.Equals(httpRequest.Method, "POST", StringComparison.InvariantCultureIgnoreCase)) {
                httpRequest.ContentLength = 0;
                httpRequest.ContentType = "application/x-www-form-urlencoded";
            }
            if (cookies != null) {
                httpRequest.CookieContainer = cookies;
            }
            httpRequest.KeepAlive = false;
            return httpRequest;
        }

        public static HttpWebRequest GetRequest20(Uri requestUri, IToken token,
                    string httpMethod, string contentType, CookieContainer cookies) {
            if (token == null || token.IsEmpty) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token'");
            }
            if (requestUri == null) {
                throw new ArgumentNullException("requestUri");
            }
            if (httpMethod == null || httpMethod.Length == 0) {
                throw new ArgumentNullException("httpMethod");
            }
            if (!requestUri.IsAbsoluteUri) {
                throw new InvalidOperationException("Request URI be absolute.");
            }

            Url url = new Url(requestUri, String.Empty);

            HttpWebRequest httpRequest
                = (HttpWebRequest)HttpWebRequest.Create(url.ToUri(
                        new Parameter("access_token", token.Value)));

            httpRequest.Method = httpMethod;
            httpRequest.PreAuthenticate = true;
            httpRequest.AllowAutoRedirect = false;
            if (cookies != null) {
                httpRequest.CookieContainer = cookies;
            }

            if (String.IsNullOrEmpty(contentType)) {
                if (String.Equals(httpRequest.Method, "POST", StringComparison.InvariantCultureIgnoreCase)) {
                    httpRequest.ContentLength = 0;
                    httpRequest.ContentType = "application/x-www-form-urlencoded";
                }
            } else {
                httpRequest.ContentType = contentType;
            }

            return httpRequest;
        }

        public static HttpWebRequest GetRequest10(Uri requestUri, IToken token, 
            string httpMethod, string consumerKey, string consumerSecret, Signature signature, 
            string contentType, CookieContainer cookies) {
            
            if (requestUri == null) {
                throw new ArgumentNullException("requestUri");
            }
            if (!requestUri.IsAbsoluteUri) {
                throw new InvalidOperationException("Request URI be absolute.");
            }
            if (token == null) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token'");
            }
            if (String.IsNullOrEmpty(token.Value)) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token'");
            }
            if (String.IsNullOrEmpty(token.Secret)) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token_secret'");
            }
            if (String.IsNullOrEmpty(httpMethod)) {
                throw new ArgumentNullException("httpMethod");
            }
            if (String.IsNullOrEmpty(consumerKey)) {
                throw new ArgumentNullException("consumerKey");
            }
            if (String.IsNullOrEmpty(consumerSecret)) {
                throw new ArgumentNullException("consumerSecret");
            }

            List<Parameter> authParams = new List<Parameter>();

            authParams.Add(Parameter.Version());
            authParams.Add(Parameter.Nonce());
            authParams.Add(Parameter.Timestamp());
            authParams.Add(new Parameter("oauth_consumer_key", consumerKey));
            authParams.Add(new Parameter("oauth_token", token.Value));

            Url url = new Url(requestUri, String.Empty);

            switch (signature) {
                case Signature.PLAINTEXT:

                    authParams.Add(new Parameter("oauth_signature_method", "PLAINTEXT"));

                    Signing.PlainText.Sign(
                        consumerSecret,
                        token.Secret,
                        authParams);

                    break;

                case Signature.HMACSHA1:

                    authParams.Add(new Parameter("oauth_signature_method", "HMAC-SHA1"));

                    Signing.HmaSha1.Sign(
                        httpMethod,
                        url,
                        consumerSecret,
                        token.Secret,
                        authParams);

                    break;

                default:
                    throw new NotImplementedException();
            }

            HttpWebRequest httpRequest
                = (HttpWebRequest)HttpWebRequest.Create(url.ToUri(null));

            httpRequest.Method = httpMethod;
            httpRequest.PreAuthenticate = true;
            httpRequest.AllowAutoRedirect = false;
            if (cookies != null) {
                httpRequest.CookieContainer = cookies;
            }
            if (String.IsNullOrEmpty(contentType)) {

                if (String.Equals(httpRequest.Method, "POST", StringComparison.InvariantCultureIgnoreCase)) {
                    httpRequest.ContentLength = 0;
                    httpRequest.ContentType = "application/x-www-form-urlencoded";
                }

            } else {
                httpRequest.ContentType = contentType;
            }

            StringBuilder authorizationHeader = new StringBuilder();

            authorizationHeader.Append("OAuth");

            for (int i = 0; i < authParams.Count; i++) {
                if (authParams[i].IsEmpty) {
                    continue;
                }
                if (i == 0) {
                    authorizationHeader.Append(" ");
                } else {
                    authorizationHeader.Append(",");
                }
                authorizationHeader.AppendFormat("{0}=\"{1}\"",
                    Escaping.Escape(authParams[i].Name),
                    Escaping.Escape(authParams[i].Value));
            }

            httpRequest.Headers.Add(HttpRequestHeader.Authorization, authorizationHeader.ToString());

            return httpRequest;

        }

        public static string ParseResource(StreamReader reader) {
            if (reader == null) {
                throw new ArgumentNullException("reader");
            }

            return reader.ReadToEnd();
        }

        public static string ParseResource(Stream stream) {
            if (stream == null) {
                throw new ArgumentNullException("stream");
            }

            using (StreamReader reader = new StreamReader(stream)) {
                return ParseResource(reader);
            }
        }

        public static string ParseResource(WebResponse response) {
            if (response == null) {
                throw new ArgumentNullException("response");
            }

            using (Stream stream = response.GetResponseStream()) {
                return ParseResource(stream);
            }
        }

        public string GetResource(Uri requestUri) { return GetResource(requestUri, _accessToken, "1.0"); }
        public string GetResource(Uri requestUri, IToken token) { return GetResource(requestUri, token, "1.0"); }
        public string GetResource(Uri requestUri, IToken token, string version) {
            if (version == null 
                        || version.Length == 0) {
                version = "1.0";
            }

            bool v20 = false;
            if (!String.Equals(version, "1.0") &&
                        !String.Equals(version, "2.0")) {                            
                throw new ArgumentException("The specified OAuth version is not supported.", "version");
            }
            if (String.Equals(version, "2.0")) {
                v20 = true;
            }

            HttpWebRequest request = v20 ?
                    GetRequest20(requestUri, 
                        token, 
                        this.HttpMethod, 
                        String.Empty,
                        this.Cookies) :
                    GetRequest10(requestUri, 
                        token, 
                        this.HttpMethod, 
                        this.ConsumerKey, 
                        this.ConsumerSecret, 
                        this.Signature, 
                        String.Empty,
                        this.Cookies);
            
            try {
                HttpStatusCode statusCode = HttpStatusCode.OK;
                string statusDescription = String.Empty;
                string redirectUri = String.Empty;

#if TRACE
                Trace.WriteLine(request.RequestUri.ToString());
#endif
                
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {                    
                    statusCode = response.StatusCode;
                    statusDescription = response.StatusDescription;
                    redirectUri = response.Headers["Location"];                    

                    if (statusCode == HttpStatusCode.OK) {
                        return ParseResource(response);
                    }
                }

                Debug.Assert(statusCode != HttpStatusCode.OK, "statusCode != HttpStatusCode.OK");

                if (statusCode == HttpStatusCode.Redirect
                                && !String.IsNullOrEmpty(redirectUri)) {                                    
                    request = v20 ? 
                        GetRequest20(
                            new Uri(redirectUri, UriKind.Absolute), 
                            token, 
                            this.HttpMethod, 
                            String.Empty,
                            this.Cookies) :
                        GetRequest10(
                            new Uri(redirectUri, UriKind.Absolute), 
                            token, 
                            this.HttpMethod, 
                            this.ConsumerKey, 
                            this.ConsumerSecret, 
                            this.Signature, 
                            String.Empty,
                            this.Cookies);

                    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
                        statusCode = response.StatusCode;
                        statusDescription = response.StatusDescription;
                        if (statusCode == HttpStatusCode.OK) {
                            return ParseResource(response);
                        }
                    }
                }

                throw new WebException(statusDescription);

            } catch {
                throw;
            }

        }

        string _httpMethod = "GET";
        /// <summary>
        /// </summary>
        public string HttpMethod {
            get { 
                return _httpMethod; 
            }
            set {
                _httpMethod = value;
            }
        }        

        Uri _requestUri;
        /// <summary>
        /// Specifies the URI to be used for acquiring a request token.
        /// </summary>
        public Uri RequestUri {
            get {
                return _requestUri;
            }
            set {
                _requestUri = value;
            }
        }

        Uri _authorizeUri;
        /// <summary>
        /// Specifies the URI to be used when making an authorize request.
        /// </summary>
        public Uri AuthorizeUri {
            get {
                return _authorizeUri;
            }
            set {
                _authorizeUri = value;
            }
        }

        Uri _accessUri;
        /// <summary>
        /// Specifies the URI to be used when making an access token request.
        /// </summary>
        public Uri AccessUri {
            get {
                return _accessUri;
            }
            set {
                _accessUri = value;
            }
        }        

        Signature _signature;
        /// <summary>
        /// Specifies the signature algorithm to be used when signing requests. OAuth: oauth_signature_method
        /// </summary>
        public Signature Signature {
            get {
                return _signature;
            }
            set {
                _signature = value;
            }
        }

        IToken _requestToken;
        public IToken RequestToken {
            get {
                return _requestToken;
            }
            set {
                _requestToken = value;
            }
        }

        public Uri GetRequestTokenUrl() {

            if (RequestUri == null) {
                throw new InvalidOperationException("RequestUri is not specified.");
            }
            if (!RequestUri.IsAbsoluteUri) {
                throw new InvalidOperationException("RequestUri be an absolute uri.");
            }
            if (String.IsNullOrEmpty(ConsumerKey)) {
                throw new InvalidOperationException("ConsumerKey is not specified. 'oauth_consumer_key' is a required attribute.");
            }
            if (String.IsNullOrEmpty(ConsumerSecret)) {
                throw new InvalidOperationException("ConsumerSecret is not specified. 'oauth_consumer_secret' is a required attribute.");
            }
            if (CallbackUri == null) {
                throw new InvalidOperationException("CallbackUri is not specified. 'oauth_callback' is a required attribute.");
            }

            List<Parameter> parameters = new List<Parameter>();

            parameters.Add(Parameter.Version());
            parameters.Add(Parameter.Nonce());
            parameters.Add(Parameter.Timestamp());
            parameters.Add(Parameter.ConsumerKey(ConsumerKey));
            parameters.Add(Parameter.Callback(CallbackUri.ToString()));

            Url url = new Url(RequestUri, String.Empty);

            switch (Signature) {
                case Signature.PLAINTEXT:

                    parameters.Add(Parameter.SignatureMethod(Signature.PLAINTEXT));

                    Signing.PlainText.Sign(
                        ConsumerSecret,
                        String.Empty,
                        parameters);

                    break;

                case Signature.HMACSHA1:

                    parameters.Add(Parameter.SignatureMethod(Signature.HMACSHA1));

                    Signing.HmaSha1.Sign(
                        HttpMethod,
                        url,
                        ConsumerSecret,
                        String.Empty,
                        parameters);

                    break;

                default:
                    throw new NotImplementedException();
            }

            return url.ToUri(parameters);

        }

#if TEST
        public IToken GetRequestToken(ServiceProvider serviceProvider) {
            if (_requestToken != null
                        && !_requestToken.IsEmpty) {
                return _requestToken;
            }
            Response response = ServiceProvider.GetRequestToken(
                serviceProvider,
                HttpMethod,
                GetRequestTokenUrl());
            if (response.StatusCode != 200) {
                throw new WebException(String.Format("Http Error {0}. {1}", response.StatusCode, response.Content));
            }
            _requestToken = new Token(
                Parameters.ParseTokens(response.Content, true),
                ConsumerKey,
                ConsumerSecret, 
                CallbackUri.ToString(),
                "1.0");
            return _requestToken;
        }
#endif

        CookieContainer _cookies = new CookieContainer();
        public CookieContainer Cookies {
            get { 
                return _cookies; 
            }
            set {
                _cookies = value;
            }
        }

        public IToken GetRequestToken() {
            if (_requestToken != null 
                        && !_requestToken.IsEmpty) {                
                return _requestToken;
            }
            using (WebResponse httpResponse 
                        = GetRequest(
                                this.GetRequestTokenUrl(), 
                                this.HttpMethod, 
                                this.Cookies).GetResponse()) {
                _requestToken = new Token(
                    Parameters.Parse(httpResponse),
                    ConsumerKey,
                    ConsumerSecret,
                    CallbackUri.ToString(),
                    "1.0");                
                return _requestToken;
            }
        }

        bool _requireSsl = true;
        public bool RequireSsl {
            get {
                return _requireSsl;
            }
            set {
                _requireSsl = value;
            }
        }

        public Uri GetAuthorizeTokenUrl(IToken token) {
            if (token == null) {
                throw new ArgumentNullException("token");
            }
            if (AuthorizeUri == null) {
                throw new InvalidOperationException("AuthorizeUri is not specified.");
            }
            if (!AuthorizeUri.IsAbsoluteUri) {
                throw new InvalidOperationException("AuthorizeUri be an absolute uri.");
            }
            if (String.IsNullOrEmpty(token.Value)) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token'");
            }
            if (String.IsNullOrEmpty(token.Secret)) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token_secret'");
            }
            return new Url(AuthorizeUri, String.Empty).ToUri(Parameter.Token(token.Value));
        }

        public Uri GetAuthorizeTokenUrl20() {

            if (AuthorizeUri == null) {
                throw new InvalidOperationException("AuthorizeUri is not specified.");
            }
            if (!AuthorizeUri.IsAbsoluteUri) {
                throw new InvalidOperationException("AuthorizeUri be an absolute uri.");
            }
            if (!String.Equals(AuthorizeUri.Scheme, "HTTPS", StringComparison.OrdinalIgnoreCase)
                            && RequireSsl) {                                
                throw new InvalidOperationException("AuthorizeUri must use the HTTPS protocol.");
            }
            if (String.IsNullOrEmpty(ConsumerKey)) {
                throw new InvalidOperationException("ConsumerKey is not specified. 'client_id' is a required attribute.");
            }
            if (CallbackUri == null) {
                throw new InvalidOperationException("CallbackUri is not specified. 'redirect_uri' is a required attribute.");
            }
            if (!CallbackUri.IsAbsoluteUri) {
                throw new InvalidOperationException("CallbackUri be an absolute uri.");
            }

            return new Url(AuthorizeUri, String.Empty).ToUri(
                new Parameter("client_id", ConsumerKey),
                new Parameter("redirect_uri", CallbackUri.ToString()));

        }

        IToken _accessToken;
        public IToken AccessToken {
            get {
                return _accessToken;
            }
            set {
                _accessToken = value;
            }
        }

        public Uri GetAccessTokenUrl(IToken token, string verifier) {
            if (token == null) {
                throw new ArgumentNullException("token");
            }
            if (CallbackUri == null) {
                throw new InvalidOperationException("CallbackUri is not specified. 'redirect_uri' is a required attribute.");
            }
            if (AccessUri == null) {
                throw new InvalidOperationException("AccessUri is not specified.");
            }
            if (!AccessUri.IsAbsoluteUri) {
                throw new InvalidOperationException("AccessUri be an absolute uri.");
            }
            if (String.IsNullOrEmpty(ConsumerKey)) {
                throw new InvalidOperationException("ConsumerKey is not specified. 'oauth_consumer_key' is a required attribute.");
            }
            if (String.IsNullOrEmpty(ConsumerSecret)) {
                throw new InvalidOperationException("ConsumerSecret is not specified. 'oauth_consumer_secret' is a required attribute.");
            }
            if (String.IsNullOrEmpty(token.Value)) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token'");
            }
            if (String.IsNullOrEmpty(token.Secret)) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'oauth_token_secret'");
            }
            if (String.IsNullOrEmpty(verifier)) {
                throw new InvalidOperationException("The specified request is invalid. Paramter: 'oauth_verifier' is missing.");
            }

            List<Parameter> parameters = new List<Parameter>();

            parameters.Add(Parameter.Version());
            parameters.Add(Parameter.Nonce());
            parameters.Add(Parameter.Timestamp());
            parameters.Add(Parameter.ConsumerKey(ConsumerKey));
            parameters.Add(Parameter.Token(token.Value));
            parameters.Add(Parameter.Verifier(verifier));

            Url url = new Url(AccessUri, String.Empty);

            switch (Signature) {
                case Signature.PLAINTEXT:

                    parameters.Add(Parameter.SignatureMethod(Signature.PLAINTEXT));

                    Signing.PlainText.Sign(
                        ConsumerSecret,
                        token.Secret,
                        parameters);

                    break;

                case Signature.HMACSHA1:

                    parameters.Add(Parameter.SignatureMethod(Signature.HMACSHA1));

                    Signing.HmaSha1.Sign(
                        HttpMethod,
                        url,
                        ConsumerSecret,
                        token.Secret,
                        parameters);

                    break;

                default:
                    throw new NotImplementedException();
            }

            return url.ToUri(parameters);
        }
       
        public Uri GetAccessTokenUrl20(string code) {
            if (AccessUri == null) {
                throw new InvalidOperationException("AccessUri is not specified.");
            }
            if (!AccessUri.IsAbsoluteUri) {
                throw new InvalidOperationException("AccessUri be an absolute uri.");
            }
            if (!String.Equals(AccessUri.Scheme, "HTTPS", StringComparison.OrdinalIgnoreCase) 
                            && RequireSsl) {
                throw new InvalidOperationException("AccessUri must use the HTTPS protocol.");
            }
            if (CallbackUri == null) {
                throw new InvalidOperationException("CallbackUri is not specified. 'redirect_uri' is a required attribute.");
            }
            if (!CallbackUri.IsAbsoluteUri) {
                throw new InvalidOperationException("CallbackUri be an absolute uri.");
            }
            if (String.IsNullOrEmpty(ConsumerKey)) {
                throw new InvalidOperationException("ConsumerKey is not specified. 'client_id' is a required attribute.");
            }
            if (String.IsNullOrEmpty(ConsumerSecret)) {
                throw new InvalidOperationException("ConsumerSecret is not specified. 'client_secret' is a required attribute.");
            }
            if (String.IsNullOrEmpty(code)) {
                throw new InvalidOperationException("The specified request token is invalid. Paramter: 'code'");
            }

            List<Parameter> parameters = new List<Parameter>();
            
            parameters.Add(new Parameter("client_id", ConsumerKey));
            parameters.Add(new Parameter("client_secret", ConsumerSecret));
            parameters.Add(new Parameter("code", code));
            parameters.Add(new Parameter("redirect_uri", CallbackUri.ToString()));

            Url url = new Url(AccessUri, String.Empty);
            return url.ToUri(parameters);
        }

#if TEST
        public IToken GetAccessToken(ServiceProvider serviceProvider, IToken requestToken, string verifier) {
            if (_accessToken != null
                        && !_accessToken.IsEmpty) {
                return _accessToken;
            }
            Response response = ServiceProvider.GetAccessToken(
                serviceProvider,
                HttpMethod,
                GetAccessTokenUrl(requestToken, verifier));
            if (response.StatusCode != 200) {
                throw new WebException(String.Format("Http Error {0}. {1}", response.StatusCode, response.Content));
            }
            _accessToken = new Token(
                Parameters.ParseTokens(response.Content, true),
                ConsumerKey,
                ConsumerSecret,
                CallbackUri.ToString(),
                "1.0");
            return _accessToken;
        }
#endif

        public IToken GetAccessToken(IToken requestToken, string verifier) {
            if (_accessToken != null
                        && !_accessToken.IsEmpty) {
                return _accessToken;
            }
            using (WebResponse httpResponse
                    = GetRequest(
                        GetAccessTokenUrl(requestToken, verifier), 
                        this.HttpMethod, 
                        this.Cookies).GetResponse()) {
                _accessToken = new Token(
                    Parameters.Parse(httpResponse),
                    ConsumerKey,
                    ConsumerSecret,
                    CallbackUri.ToString(),
                    "1.0");
                return _accessToken;
            }
        }

        public IToken GetAccessToken20(string code) {
            if (_accessToken != null
                        && !_accessToken.IsEmpty) {            
                return _accessToken;
            }
            using (WebResponse httpResponse 
                        = GetRequest(
                                    GetAccessTokenUrl20(code), 
                                    this.HttpMethod, 
                                    this.Cookies).GetResponse()) {
                _accessToken = new Token(
                    Parameters.Parse(
                        httpResponse, 
                        false /* OAuth 2.0 token do not have to be percent escaped */ ),
                    ConsumerKey,
                    ConsumerSecret,
                    CallbackUri.ToString(),
                    "2.0");
                return _accessToken;
            }
        }

    }
}